package be.nvlooy.moviereminder.service.implementations;

import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import be.nvlooy.moviereminder.entities.Collection;
import be.nvlooy.moviereminder.entities.Media;
import be.nvlooy.moviereminder.entities.Reminder;
import be.nvlooy.moviereminder.entities.User;
import be.nvlooy.moviereminder.exception.ServiceException;
import be.nvlooy.moviereminder.service.BasicService;
import be.nvlooy.moviereminder.service.CollectionService;

@Service
@Scope("singleton")
public class CollectionServiceImpl extends BasicService implements CollectionService {
	
	private EntityManager em;
	
	/**
	 * A Map containing the columns 
	 */
	private Map<String, String> sortingColumns = new HashMap<String, String> ();
	
	@Autowired
	public void setEntityManager(EntityManager em) {
		this.em = em;
	}
	
	@Override
	public Reminder addReminder(User user, Media media) {
		return null;
	}

	@Override
	public void removeReminder(User user, Media media) {
	}

	@Override
	public void removeReminder(int id) {		
	}

	@Override
	public void sendSuggestion(User user, User toUser, Media media) {		
	}
	
	public CollectionServiceImpl() {
		sortingColumns.put("default", "m.releasedDate");
		sortingColumns.put("alpha", "m.name");
		sortingColumns.put("release", "m.releasedDate");
		sortingColumns.put("rating", "m.rating");
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public Collection addMedia(User user, Media media) {
		Collection collection = new Collection();
		collection.setUser(user);
		collection.setMedia(media);
		
		try {
			em.persist(collection);
		}
		catch (RuntimeException e) {
			throw new ServiceException("collectionAlreadyAdded", e);
		}
		
		return collection;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public void removeCollection(User user, Media media) {
		Collection item = getCollectionItem(user, media);

		try {
			em.remove(item);
		}
		catch (RuntimeException e) {
			throw new ServiceException("collectionRemoveFail", e);
		}
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public Collection getCollectionItem(User user, Media media) {
		Collection collectionItem = null;
		
		Query query = em.createNamedQuery("Collection.getByUserAndMedia");
		query.setParameter("user", user);
		query.setParameter("media", media);
		
		try {
			collectionItem = (Collection) query.getSingleResult();
		}
		catch(javax.persistence.NoResultException ex) {}
		
		return collectionItem;
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRED)
	public Collection setMustSee(User user, int collectionID, boolean mustSee) {
		Collection collItem = getCollectionItemByID(collectionID);
		collItem.setMustSee(mustSee);
		
		em.persist(collItem);
		
		return collItem;
	}

	@Override
	public Collection getCollectionItemByID(int collectionID) {
		Collection collectionItem = null;
		
		collectionItem = (Collection) em.find(Collection.class, (long) collectionID);
		
		return collectionItem;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Collection> getCollectionByUser(User user) {
		List<Collection> items = null;
		Query query = em.createNamedQuery("Collection.getByUser");
		query.setParameter("user", user);
		
		try {
			items = query.getResultList();
		}
		catch(javax.persistence.NoResultException ex) {}
		
		return items;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Collection> searchCollectionItems(User user, String search, String sortOn, 
			String sortOrder, Boolean mustsee, Boolean suggested) {
		StringBuffer sqlSelect = new StringBuffer();
		StringBuffer sqlQuery = new StringBuffer();
		StringBuffer sqlGroupBy = new StringBuffer();
		String sortColumn;
		List<Collection> items = null;
		
		// check if we can sort on a given column
		if(sortingColumns.containsKey(sortOn))
			sortColumn = sortingColumns.get(sortOn);
		else
			sortColumn = sortingColumns.get("default");
		
		if(!(sortOrder != null && sortOrder.equals("asc")))
			sortOrder = "desc";
		
		sqlSelect.append("SELECT c FROM Collection AS c " +
			"JOIN c.media as m ");
		
		if(suggested != null) {
			if(suggested) {
				sqlSelect.append("JOIN c.suggestions s ");
				sqlGroupBy.append(" GROUP BY c.id ");
			}
			else
				sqlQuery.append(" AND not exists elements(c.suggestions)");
		}
		
		if(search != null && !search.isEmpty())
			sqlQuery.append("AND LOWER(m.name) LIKE LOWER(:search) ");
		
		if(mustsee != null) {
			if(mustsee)
				sqlQuery.append("AND c.mustSee = 1 ");
			else
				sqlQuery.append("AND c.mustSee = 0 ");
		}
		
		sqlSelect.append("WHERE c.user = :user ")
			.append(sqlQuery.toString())
			.append(sqlGroupBy.toString())
			.append("ORDER BY " + sortColumn + " " + sortOrder);

		Query query = em.createQuery(sqlSelect.toString());
		query.setParameter("user", user);
		
		if(search != null && !search.isEmpty())
			query.setParameter("search", "%"+search+"%");
		
		try {
			items = query.getResultList();
		}
		catch(javax.persistence.NoResultException ex) {}
		
		return items;
	}

}
